package com.codejoys.monitor;

import com.codejoys.monitor.jna.CANLib;
import com.sun.jna.Native;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import org.controlsfx.control.StatusBar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Function;

public class MainController implements Initializable {
    private static Logger logger = LoggerFactory.getLogger(MainController.class);

    @FXML
    public ChoiceBox<Integer> choiceCanDevices;

    @FXML
    public ChoiceBox<Integer> choiceModules;

    @FXML
    public TextField txtVoltage;

    @FXML
    public TextField txtCurrent;

    @FXML
    TextField txtSocketAddress;

	@FXML
    TextField txtSocketPort;

    Executor executor = Executors.newSingleThreadExecutor();

    public static CANLib lib;

    @FXML
    StatusBar statusBar;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
        lib = Native.load("CanLib", CANLib.class);
        final int num = lib.InitCanDev();
        statusBar.setText("加载CAN驱动成功！设备数目：" + num);

        choiceCanDevices.getItems().addAll(0, 1, 2, 3);
        choiceCanDevices.getSelectionModel().selectFirst();

        for (int i = 1; i <= 36; i++) {
            choiceModules.getItems().add(i);
        }

        choiceModules.getSelectionModel().selectFirst();
	}

    public void onOpenCan(ActionEvent actionEvent) {
        System.out.println("openCan");

        executeCommand(lib::OPenCanDev, "打开CAN结果：");
    }

    public void executeCommand(Function<Integer, Boolean> func, String msg) {
        Integer canIndex = choiceCanDevices.getSelectionModel().getSelectedItem();
        executor.execute(() -> {
            final Boolean result = func.apply(canIndex);
            Platform.runLater(() -> {
                statusBar.setText(msg + result);
            });
        });
    }

    public void onCloseCan(ActionEvent actionEvent) {
	    executeCommand(lib::CloseCanDev, "关闭CAN结果：");
    }

    public void onOpenModule(ActionEvent actionEvent) {
	    int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();

        executor.execute(() -> {
            final int result = lib.TurnOnOffModule(cId, 0, (byte)1, (byte)mId, 1);
            Platform.runLater(() -> {
                statusBar.setText("打开模块："
                        + (result == 0 ? "成功！" : "失败！")
                        + " result: " + Long.toHexString(result));
            });
        });
    }

    public void onCloseModule(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();

        executor.execute(() -> {
            final int result = lib.TurnOnOffModule(0, cId, (byte)1, (byte)mId, 0);
            Platform.runLater(() -> {
                statusBar.setText("关闭模块"
                        + (result == 0 ? "成功！" : "失败！")
                        + " result: " + Long.toHexString(result));
            });
        });
    }

    public void onReadVoltage(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();

        executor.execute(() -> {
            final int result = lib.GetModuleVoltage(0, cId, (byte)1, (byte)mId);
            Platform.runLater(() -> {
                if (result == 0xFFFF) {
                    statusBar.setText("读取电压错误！");
                } else {
                    statusBar.setText("电压值：" + (result / 1000) + " (V)");
                }
            });
        });
    }

    public void onReadCurrent(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();

        executor.execute(() -> {
            final int result = lib.GetModuleCurrent(0, cId, (byte) 1, (byte)mId);
            Platform.runLater(() -> {
                if (result == 0xFFFF) {
                    statusBar.setText("读取电流错误！");
                } else {
                    statusBar.setText("电流值：" + (result / 1000) + " (A)");
                }
            });
        });
    }

    public void onReadTemperature(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();

        executor.execute(() -> {
            final int result = lib.GetModuleTemperature(0, cId, (byte)1, (byte)mId);
            // final int result = lib.GetModuleStatus(0, 0, (byte)1, (byte)1);
            Platform.runLater(() -> {
                if (result == 0xFFFF) {
                    statusBar.setText("读取温度错误！");
                } else {
                    statusBar.setText("温度值：" + (result / 1000) + " (℃)");
                }
            });
        });
    }

    public void onSetVoltage(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();
        double v = Double.parseDouble(txtVoltage.getText());

        executor.execute(() -> {
            final int result = lib.SetModuleVoltage(0, cId, (byte)1, (byte)mId, v);
            Platform.runLater(() -> {
                if (result == 0xFFFF) {
                    statusBar.setText("设置电压错误！");
                } else {
                    statusBar.setText("设置成功，电压：" + (result / 1000) + " (V)");
                }
            });
        });
    }

    public void onSetCurrent(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();
        double c = Double.parseDouble(txtCurrent.getText());

        executor.execute(() -> {
            final int result = lib.SetModuleCurrent(0, cId, (byte)1, (byte)mId, c);
            Platform.runLater(() -> {
                if (result == 0xFFFF) {
                    statusBar.setText("设置电流错误！");
                } else {
                    statusBar.setText("设置成功，电流值：" + (result / 1000) + " (A)");
                }
            });
        });
    }

    private Socket socket;
    public void onOpenSocket(ActionEvent actionEvent) {
        String address = txtSocketAddress.getText();
        String port = txtSocketPort.getText();
        System.out.println("socket address:" + address + ":" + port);

        if (address.length() == 0 || port.length() == 0) {
            statusBar.setText("请输入ip和端口");
            return;
        }

        executor.execute(() -> {
            try {
                Platform.runLater(() -> statusBar.setText("正在打开。。。"));
                if (socket != null) {
                    socket.close();
                }

                socket = new Socket();
                socket.setSoTimeout(6000);  // read timeout, not connect time out
                socket.setKeepAlive(true);
                socket.setOOBInline(true);
                socket.connect(new InetSocketAddress(address, Integer.valueOf(port)), 2000);

                Platform.runLater(() -> statusBar.setText("打开socket成功！"));
            } catch (IOException e) {
                e.printStackTrace();
                Platform.runLater(() -> statusBar.setText("打开socket失败！"));
                try {
                    socket.close();
                    socket = null;
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    private static String formatBytes(byte[] bytes, int read) {
	    if (read >= bytes.length) {
	        read = bytes.length;
        }

	    StringBuilder sb = new StringBuilder();
	    for (int i = 0; i < read; i++) {
	        sb.append(String.format("%02X", bytes[i]));
        }

	    return sb.toString();
    }

    public void onCloseSocket(ActionEvent actionEvent) {
        executor.execute(() -> {
            if (socket == null) return;
            try {
                Platform.runLater(() -> statusBar.setText("正在关闭。。。"));
                socket.close();
                Platform.runLater(() -> statusBar.setText("关闭socket成功！"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    public void onOpenPower(ActionEvent actionEvent) {
        if (socket == null) {
            statusBar.setText("socket未打开。");
            return;
        }

        toggleOpen(true);
    }

    public void onClosePower(ActionEvent actionEvent) {
        if (socket == null) {
            statusBar.setText("socket未打开。");
            return;
        }

        toggleOpen(false);
    }

    private void toggleOpen(boolean open) {
        // 电源序号      1#   #2   3#   4#   5#   6#  ...  17#   18#
        // 启动地址      0    1    2     3    4    5  ...  16    17   （十进制表示）
        // 停止地址      20   21   22    23   24   25 ...  36    37   （十进制表示）
        int module = choiceModules.getSelectionModel().getSelectedItem();
        byte address = (byte) (module - 1);    // 第二个
        byte mId = open ? address : (byte) (address + 20);// 开关区别在于地址不一样

        String ip = txtSocketAddress.getText();
        int port = Integer.valueOf(txtSocketPort.getText());

        executor.execute(() -> {
            try {
                Platform.runLater(() -> statusBar.setText("正在发送。。。"));

                byte[] sendData = {
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x05,     // 前8个字节固定
                        0x00, mId,     // 9，10字节表示地址，从00开始
                        (byte)0xff, 0x00    // 0xFF表示按下，00表示松开
                };

                socket.getOutputStream().write(sendData);
                socket.getOutputStream().flush();

                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                byte[] resultData = new byte[100];
                int read = socket.getInputStream().read(resultData, 0, 100);
                String result = formatBytes(resultData, read);

                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                byte[] resetData = {
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x05,     // 前8个字节固定
                        0x00, mId,
                        0x00, 0x00
                };
                socket.getOutputStream().write(resetData);
                socket.getOutputStream().flush();

                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                resultData = new byte[100];
                read = socket.getInputStream().read(resultData, 0, 100);
                result = result + " / " + formatBytes(resultData, read);

                final String msg = result;

                Platform.runLater(() -> statusBar.setText((open ? "打开" : "关闭") + "成功！返回结果：" + msg));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    public void onSendTpr(ActionEvent actionEvent) {
        if (socket == null) {
            statusBar.setText("socket未打开。");
            return;
        }
    }

    // 读取所有模块状态
    public void onReadStatus(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        executor.execute(() -> {
            try {
                for (int i = 1; i <= 36; i++) {
                    final int status = lib.GetModuleStatus(cId, 0, 1, i);
                    boolean isPowerOff = (status & (1 << 24)) == 0;

                    logger.info("模块已关机？：" + isPowerOff + " status: " + Integer.toBinaryString(status));

                    Thread.sleep(30);
                }
            } catch (Exception e) {
                logger.error("读取模块状态异常！", e);
            }
        });
    }

    public void onReadOneStatus(ActionEvent actionEvent) {
        int cId = choiceCanDevices.getSelectionModel().getSelectedItem();
        int mId = choiceModules.getSelectionModel().getSelectedItem();
        executor.execute(() -> {
            try {
                final int status = lib.GetModuleStatus(cId, 0, 1, mId);
                boolean isPowerOff = (status & (1 << 24)) == 0;

                logger.info("模块已关机？：" + isPowerOff + " status: " + Integer.toBinaryString(status));
            } catch (Exception e) {
                logger.error("读取模块状态异常！", e);
            }
        });
    }
}
